package com.ldf.jrtsp.player;

import cn.hutool.core.util.StrUtil;
import com.ldf.jrtsp.callback.BareStreamCallBack;
import com.ldf.jrtsp.callback.OptionsReplyCallBack;
import com.ldf.jrtsp.conf.RtspConfig;
import com.ldf.jrtsp.enums.*;
import com.ldf.jrtsp.exception.JRtspException;
import com.ldf.jrtsp.parser.*;
import com.ldf.jrtsp.pool.JRtspThreadPool;
import com.ldf.jrtsp.protocol.DelimiterProtocol;
import com.ldf.jrtsp.socket.IRtspSocket;
import com.ldf.jrtsp.socket.RtspTransportFactory;
import com.ldf.jrtsp.task.RtspKeepAliveTask;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.DataInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketAddress;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Timer;
import java.util.concurrent.atomic.AtomicBoolean;

import static com.ldf.jrtsp.constants.RtspConstants.*;
import static com.ldf.jrtsp.enums.RtspOptionsType.*;
import static com.ldf.jrtsp.enums.RtspProtocolType.RTSP_OVER_UDP;

/**
 * rtsp播放器
 *
 * @author lidaofu
 * @since 2024/6/19
 **/
public class RtspPlayer implements IRtspPlayer, Runnable {
    private final static Logger log = LoggerFactory.getLogger(RtspPlayer.class);
    private RtspUrlParser rtspUrlParser;
    private RtspSdpParser rtspSdpParser;
    private RtspConfig rtspConfig;
    private Socket socket;
    private OutputStream outputStream;
    private DataInputStream inputStream;
    private RtspAuthType rtspAuthType = RtspAuthType.NONE;
    private RtspProtocolType rtspProtocolType;
    private BareStreamCallBack bareStreamCallBack;
    private OptionsReplyCallBack optionsReplyCallBack;
    private IRtpLoadCodecParser videoCodecParser;
    private IRtpLoadCodecParser audioCodecParser;
    private Timer timer;
    private RtspKeepAliveTask rtspKeepAliveTask;
    private String session;
    private String ssrc;
    private String uri;
    private List<String> options;
    private int timeout;
    private float scale = 1.0f;
    private String authInfo;
    private int videoRtpPort;
    private int audioRtpPort;
    private int remoteVideoRtpPort;
    private int remoteAudioRtpPort;
    private int seq = 0;
    private AtomicBoolean isStop = new AtomicBoolean(false);
    private byte[] buffer = new byte[4096];
    private ByteBuffer byteBuffer = ByteBuffer.allocate(4096);
    private RtspOptionsType seqType[] = new RtspOptionsType[16];

    public RtspPlayer(BareStreamCallBack bareStreamCallBack) {
        this.rtspConfig = new RtspConfig();
        this.bareStreamCallBack = bareStreamCallBack;
        this.optionsReplyCallBack = null;
    }

    public RtspPlayer(RtspConfig rtspConfig, BareStreamCallBack bareStreamCallBack) {
        this.rtspConfig = rtspConfig;
        this.bareStreamCallBack = bareStreamCallBack;
        this.optionsReplyCallBack = null;
    }

    public RtspPlayer(BareStreamCallBack bareStreamCallBack, OptionsReplyCallBack optionsReplyCallBack) {
        this.rtspConfig = new RtspConfig();
        this.bareStreamCallBack = bareStreamCallBack;
        this.optionsReplyCallBack = optionsReplyCallBack;
    }

    public RtspPlayer(RtspConfig rtspConfig, BareStreamCallBack bareStreamCallBack, OptionsReplyCallBack optionsReplyCallBack) {
        this.rtspConfig = rtspConfig;
        this.bareStreamCallBack = bareStreamCallBack;
        this.optionsReplyCallBack = optionsReplyCallBack;
    }


    @Override
    public void play(String url) {
        play(url, 1.0f, RTSP_OVER_UDP);
    }

    @Override
    public void play(String url, float scale) {
        play(url, scale, RTSP_OVER_UDP);
    }

    @Override
    public void play(String url, RtspProtocolType rtspProtocolType) {
        play(url, 1.0f, rtspProtocolType);
    }

    @Override
    public void play(String url, float scale, RtspProtocolType rtspProtocolType) {
        this.scale = scale;
        this.rtspProtocolType = rtspProtocolType;
        try {
            //解析rtsp url
            this.rtspUrlParser = new RtspUrlParser(url);
        } catch (Exception e) {
            log.error("rtsp url parse error", e);
            throw new JRtspException("rtsp url parse error", e);
        }
        //开始连接
        startConnect();
    }


    @Override
    public void pause(boolean pause) {
        sendPause();
    }

    @Override
    public void stop() {
        isStop.set(true);
        //发送teardown请求
        sendTeardown();
        sendOptionsCallBack(TEARDOWN, null);
    }

    /**
     * 开始连接
     */
    private void startConnect() {
        try {
            this.socket = new Socket();
            SocketAddress socketAddress = new InetSocketAddress(this.rtspUrlParser.getHost(), this.rtspUrlParser.getPort());
            this.socket.connect(socketAddress, RTSP_TIMEOUT);
            if (this.socket.isConnected()) {
                this.outputStream = this.socket.getOutputStream();
                this.inputStream = new DataInputStream(this.socket.getInputStream());
                //发送options请求
                sendOptions();
                //接收数据
                JRtspThreadPool.execute(this);
            }

        } catch (IOException e) {
            log.error("rtsp connect error", e);
            throw new JRtspException("rtsp connect error", e);
        }
    }

    @Override
    public void run() {
        while (!isStop.get()) {
            receiveData();
        }
    }

    /**
     * 接收数据
     */
    public void receiveData() throws RuntimeException {
        byteBuffer.compact();
        int remaining = byteBuffer.remaining();
        if (remaining > 0) {
            try {
                int read = inputStream.read(buffer, 0, remaining);
                if (read > 0) {
                    byteBuffer.put(buffer, 0, read);
                    byteBuffer.flip();
                    byteBuffer.mark();
                    byte type = byteBuffer.get();
                    byteBuffer.reset();
                    if ((type & 0xFF) != 0x24) {
                        byte[] bytes = DelimiterProtocol.decode(byteBuffer);
                        if (bytes != null) {
                            RtspDataParser rtspDataParser = new RtspDataParser(bytes);
                            String contentLengthStr = rtspDataParser.getHeaders().get("Content-Length");
                            if (StrUtil.isNotBlank(contentLengthStr)) {
                                Integer contentLength = Integer.valueOf(contentLengthStr);
                                byte[] contentByte = new byte[contentLength];
                                byteBuffer.compact();
                                if (byteBuffer.position() < contentLength) {
                                    int needReadSize = contentLength - byteBuffer.position();
                                    inputStream.readFully(buffer, 0, needReadSize);
                                    byteBuffer.put(buffer, 0, needReadSize);
                                }
                                byteBuffer.flip();
                                byteBuffer.get(contentByte);
                                rtspDataParser.setSdp(new String(contentByte));
                            }
                            String cSeqStr = rtspDataParser.getHeaders().get("CSeq");
                            if (StrUtil.isNotBlank(cSeqStr)) {
                                Integer cSeq = Integer.valueOf(cSeqStr);
                                if (seqType[cSeq % 16] != null) {
                                    seqType[cSeq % 16].handle(this, rtspDataParser);
                                }
                            }
                        }
                    } else {
                        byteBuffer.get(buffer, 0, 4);
                        int channelId = (buffer[1] & 0xFF);
                        int rtpDataSize = (buffer[2] & 0xFF) << 8 | (buffer[3] & 0xFF);
                        receiveRtpData(channelId, rtpDataSize);
                    }
                }
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    }

    /**
     * 接收rtp数据
     *
     * @param channelId
     * @param rtpDataSize
     */
    private void receiveRtpData(int channelId, int rtpDataSize) {
        byteBuffer.get(buffer, 0, rtpDataSize);
        RtpDataParser rtpDataParser = new RtpDataParser(buffer, 0, rtpDataSize);
        if (rtpDataParser.getRawData() == null) {
            return;
        }
        switch (channelId) {
            case 0:
                if (videoCodecParser != null) {
                    videoCodecParser.sendRtpPacket(rtpDataParser);
                }
                break;
            case 2:
                if (audioCodecParser != null) {
                    audioCodecParser.sendRtpPacket(rtpDataParser);
                }
                break;
        }
    }

    /**
     * 发送数据
     *
     * @param data
     */
    private void sendData(String data) {
        try {
            log.debug("send data: \n{}", data);
            this.outputStream.write(data.getBytes(StandardCharsets.UTF_8));
            this.outputStream.flush();
        } catch (IOException e) {
            throw new JRtspException("rtsp send data error", e);
        }
    }

    /**
     * 发送options请求
     */
    public void sendOptions() {
        StringBuilder sb = new StringBuilder();
        sb.append(OPTIONS.getMethodName());
        sb.append(this.rtspUrlParser.getOriginalUrl());
        sb.append(RTSP_VERSION);
        sb.append(RTSP_CSEQ);
        sb.append(++seq);
        sb.append(RTSP_DELIMITER);
        sb.append(RTSP_USER_AGENT);
        sb.append(RTSP_DELIMITER);
        sendData(sb.toString());
        seqType[seq % 16] = OPTIONS;
    }

    /**
     * 发送describe请求
     */
    public void sendDescribe(String authInfo) {
        this.authInfo = authInfo;
        StringBuilder sb = new StringBuilder();
        sb.append(DESCRIBE.getMethodName());
        sb.append(this.rtspUrlParser.getOriginalUrl());
        sb.append(RTSP_VERSION);
        sb.append(RTSP_CSEQ);
        sb.append(++seq);
        sb.append(RTSP_DELIMITER);
        if (StrUtil.isNotBlank(this.authInfo)) {
            sb.append(this.rtspAuthType.calcAuthInfo(this.rtspUrlParser, authInfo, DESCRIBE.name()));
        }
        sb.append(RTSP_USER_AGENT);
        sb.append(RTSP_ACCEPT);
        sb.append(RTSP_DELIMITER);
        sendData(sb.toString());
        seqType[seq % 16] = DESCRIBE;
    }

    /**
     * 发送setup请求
     *
     * @param type
     */
    public void sendSetup(MediaType type) {
        boolean isVideo = type == MediaType.VIDEO;
        String controlUrl = isVideo ? rtspSdpParser.getVideoControlUrl() : rtspSdpParser.getAudioControlUrl();
        StringBuilder sb = new StringBuilder();
        sb.append(SETUP.getMethodName());
        sb.append(controlUrl);
        sb.append(RTSP_VERSION);
        sb.append(RTSP_CSEQ);
        sb.append(++seq);
        sb.append(RTSP_DELIMITER);
        if (StrUtil.isNotBlank(this.authInfo)) {
            sb.append(this.rtspAuthType.calcAuthInfo(this.rtspUrlParser, authInfo, SETUP.name()));
        }
        sb.append(RTSP_TRANSPORT);
        if (rtspProtocolType == RTSP_OVER_UDP) {
            sb.append(isVideo ? rtspSdpParser.getVideoProtocolType().getValue() : rtspSdpParser.getAudioProtocolType().getValue());
        } else {
            sb.append(RtspMediaProtocolType.RTP_AVP_TCP.getValue());
        }
        int rtpPort = 0;
        if (rtspProtocolType == RTSP_OVER_UDP) {
            rtpPort = RtspTransportFactory.getRtspOverUdpPort(rtspConfig, controlUrl, this, type);
        }
        int port = rtspProtocolType.addTransportInfo(sb, type, rtpPort);
        if (isVideo) {
            this.videoRtpPort = port;
        } else {
            this.audioRtpPort = port;
        }
        if (StrUtil.isNotBlank(session)) {
            sb.append(RTSP_DELIMITER);
            sb.append(RTSP_SESSION);
            sb.append(session);
        }
        sb.append(RTSP_DELIMITER);
        sb.append(RTSP_DELIMITER);
        sendData(sb.toString());
        seqType[seq % 16] = SETUP;
    }


    /**
     * 发送play请求
     */
    public void sendPlay() {
        StringBuilder sb = new StringBuilder();
        sb.append(PLAY.getMethodName());
        sb.append(this.rtspSdpParser.getControlUrl());
        sb.append(RTSP_VERSION);
        sb.append(RTSP_CSEQ);
        sb.append(++seq);
        sb.append(RTSP_DELIMITER);
        if (StrUtil.isNotBlank(this.authInfo)) {
            sb.append(this.rtspAuthType.calcAuthInfo(this.rtspUrlParser, authInfo, PLAY.name()));
        }
        sb.append(RTSP_USER_AGENT);
        sb.append(RTSP_SESSION);
        sb.append(session);
        sb.append(RTSP_DELIMITER);
        if (scale != 1.0) {
            sb.append(RTSP_SCALE);
            sb.append(scale);
            sb.append(RTSP_DELIMITER);
        }
        sb.append(RTSP_RANGE);
        sb.append(RTSP_DELIMITER);
        sendData(sb.toString());
        seqType[seq % 16] = PLAY;
    }

    /**
     * 发送play请求
     */
    public void sendPause() {
        StringBuilder sb = new StringBuilder();
        sb.append(PAUSE.getMethodName());
        sb.append(this.rtspSdpParser.getControlUrl());
        sb.append(RTSP_VERSION);
        sb.append(RTSP_CSEQ);
        sb.append(++seq);
        sb.append(RTSP_DELIMITER);
        if (StrUtil.isNotBlank(this.authInfo)) {
            sb.append(this.rtspAuthType.calcAuthInfo(this.rtspUrlParser, authInfo, PLAY.name()));
        }
        sb.append(RTSP_USER_AGENT);
        sb.append(RTSP_SESSION);
        sb.append(session);
        sb.append(RTSP_DELIMITER);
        sb.append(RTSP_DELIMITER);
        sendData(sb.toString());
        seqType[seq % 16] = PAUSE;
    }

    /**
     * 发送teardown请求
     */
    public void sendTeardown() {
        StringBuilder sb = new StringBuilder();
        sb.append(TEARDOWN.getMethodName());
        sb.append(this.rtspSdpParser.getControlUrl());
        sb.append(RTSP_VERSION);
        sb.append(RTSP_CSEQ);
        sb.append(++seq);
        sb.append(RTSP_DELIMITER);
        if (StrUtil.isNotBlank(this.authInfo)) {
            sb.append(this.rtspAuthType.calcAuthInfo(this.rtspUrlParser, authInfo, TEARDOWN.name()));
        }
        sb.append(RTSP_USER_AGENT);
        sb.append(RTSP_SESSION);
        sb.append(session);
        sb.append(RTSP_DELIMITER);
        sb.append(RTSP_DELIMITER);
        sendData(sb.toString());
        seqType[seq % 16] = TEARDOWN;
    }

    /**
     * 发送getparameter请求
     */
    public void sendGetParameter() {
        StringBuilder sb = new StringBuilder();
        sb.append(GET_PARAMETER.getMethodName());
        sb.append(this.rtspSdpParser.getControlUrl());
        sb.append(RTSP_VERSION);
        sb.append(RTSP_CSEQ);
        sb.append(++seq);
        sb.append(RTSP_DELIMITER);
        if (StrUtil.isNotBlank(this.authInfo)) {
            sb.append(this.rtspAuthType.calcAuthInfo(this.rtspUrlParser, authInfo, PLAY.name()));
        }
        sb.append(RTSP_USER_AGENT);
        sb.append(RTSP_SESSION);
        sb.append(session);
        sb.append(RTSP_DELIMITER);
        sb.append(RTSP_DELIMITER);
        sendData(sb.toString());
        seqType[seq % 16] = GET_PARAMETER;
    }


    public void setRtspAuthType(RtspAuthType type) {
        this.rtspAuthType = type;
    }

    public void setRtspSdp(RtspSdpParser rtspSdpParser) {
        this.rtspSdpParser = rtspSdpParser;
    }

    public void setSession(String session) {
        this.session = session;
    }

    public void setSsrc(String ssrc) {
        this.ssrc = ssrc;
    }

    public void setContentBase(String uri) {
        rtspUrlParser.setContentBase(uri);
    }

    public void setRemoteRtpPort(int serverPort, int clientPort) {
        if (clientPort == videoRtpPort) {
            this.remoteVideoRtpPort = serverPort;
        } else {
            this.remoteAudioRtpPort = serverPort;
        }
    }


    /**
     * 释放资源
     */
    public void release() {
        log.info("release resource");
        if (timer != null) {
            timer.cancel();
        }
        try {
            if (this.inputStream != null) {
                this.inputStream.close();
            }
        } catch (IOException e) {
            log.error("rtsp inputStream error", e);
            throw new JRtspException("rtsp inputStream error", e);
        }
        try {
            if (this.outputStream != null) {
                this.outputStream.close();
            }
        } catch (IOException e) {
            log.error("rtsp outputStream error", e);
            throw new JRtspException("rtsp outputStream error", e);
        }
        try {
            this.socket.close();
        } catch (IOException e) {
            log.error("rtsp close error", e);
            throw new JRtspException("rtsp close error", e);
        }
        IRtspSocket videoRtpSocket = RtspTransportFactory.getRtspSocket(videoRtpPort);
        if (videoRtpSocket != null) {
            videoRtpSocket.close();
        }
        IRtspSocket videoRtcpSocket = RtspTransportFactory.getRtspSocket(videoRtpPort + 1);
        if (videoRtcpSocket != null) {
            videoRtcpSocket.close();
        }
        IRtspSocket audioRtpSocket = RtspTransportFactory.getRtspSocket(audioRtpPort);
        if (audioRtpSocket != null) {
            audioRtpSocket.close();
        }
        IRtspSocket audioRtcpSocket = RtspTransportFactory.getRtspSocket(audioRtpPort + 1);
        if (audioRtcpSocket != null) {
            audioRtcpSocket.close();
        }
    }

    /**
     * 发送rtp版本数据 可不用参考vlc
     */
    public void sendVersionData() {
        MediaType[] mediaTypes = rtspSdpParser.getMediaTypes();
        for (MediaType mediaType : mediaTypes) {
            if (mediaType != null) {
                boolean isVideo = mediaType == MediaType.VIDEO;
                int port = isVideo ? videoRtpPort : audioRtpPort;
                int remotePort = isVideo ? remoteVideoRtpPort : remoteAudioRtpPort;
                IRtspSocket iRtspRtpSocket = RtspTransportFactory.getRtspSocket(port);
                if (iRtspRtpSocket != null) {
                    iRtspRtpSocket.setRemoteAddress(rtspUrlParser.getHost(), remotePort);
                }
                IRtspSocket iRtspRtcpSocket = RtspTransportFactory.getRtspSocket(port + 1);
                if (iRtspRtcpSocket != null) {
                    iRtspRtcpSocket.setRemoteAddress(rtspUrlParser.getHost(), remotePort + 1);
                }
            }
        }
    }

    /**
     * 创建rtp解析器
     */
    public void createRtpOverCodecParser() {
        IRtpLoadCodecParser videoCodecParser = this.rtspSdpParser.getVideoPayloadType().getRtpOverCodecParser(this.bareStreamCallBack);
        if (videoCodecParser != null) {
            this.videoCodecParser = videoCodecParser;
            JRtspThreadPool.execute(videoCodecParser);
        }
        RtpPayloadType audioPayloadType = this.rtspSdpParser.getAudioPayloadType();
        if (audioPayloadType != null) {
            IRtpLoadCodecParser audioCodecParser = audioPayloadType.getRtpOverCodecParser(this.bareStreamCallBack);
            if (audioCodecParser != null) {
                this.audioCodecParser = audioCodecParser;
                JRtspThreadPool.execute(audioCodecParser);
            }
        }
    }

    public void run1() {

        while (!this.socket.isClosed()) {
            try {
                int remaining = this.byteBuffer.remaining();
                if (remaining == 0) {
                    Thread.sleep(100);
                }
                inputStream.readFully(buffer, 0, remaining);
                this.byteBuffer.put(buffer);
                byte data[] = DelimiterProtocol.decode(this.byteBuffer);
                if ((data[0] & 0xFF) == 0x24) {
                    int channelId = (data[1] & 0xFF);
                    int rtpDataSize = (data[2] & 0xFF) << 8 | (data[3] & 0xFF);
                    if (rtpDataSize > RTP_MAX_MTU) {
                        log.error("rtp data size error");
                        throw new JRtspException("rtp data size error");
                    }
                    inputStream.readFully(data, 0, rtpDataSize);
                    RtpDataParser rtpDataParser = new RtpDataParser(data, 0, rtpDataSize);
                    if (rtpDataParser.getRawData() == null) {
                        continue;
                    }
                    switch (channelId) {
                        case 0:
                            if (videoCodecParser != null) {
                                videoCodecParser.sendRtpPacket(rtpDataParser);
                            }
                            break;
                        case 2:
                            if (audioCodecParser != null) {
                                audioCodecParser.sendRtpPacket(rtpDataParser);
                            }
                            break;
                    }
                }
            } catch (IOException | InterruptedException e) {
                log.error("rtsp receive data error", e);
            }
        }
    }

    /**
     * 回调
     *
     * @param rtspOptionsType
     * @param rtspDataParser
     */
    public void sendOptionsCallBack(RtspOptionsType rtspOptionsType, RtspDataParser rtspDataParser) {
        if (optionsReplyCallBack != null) {
            optionsReplyCallBack.callBack(rtspOptionsType, this, rtspDataParser);
        }
    }

    /**
     * 创建定时器
     */
    public void createRtspKeepAliveTask() {
        if (rtspProtocolType == RTSP_OVER_UDP && timer == null) {
            timer = new Timer();
            rtspKeepAliveTask = new RtspKeepAliveTask(this);
            long delay = timeout * 1000L;
            timer.schedule(rtspKeepAliveTask, delay, delay);
        }
    }

    public RtspUrlParser getRtspUrlParser() {
        return rtspUrlParser;
    }

    public void setRtspUrlParser(RtspUrlParser rtspUrlParser) {
        this.rtspUrlParser = rtspUrlParser;
    }

    public RtspSdpParser getRtspSdpParser() {
        return rtspSdpParser;
    }

    public void setRtspSdpParser(RtspSdpParser rtspSdpParser) {
        this.rtspSdpParser = rtspSdpParser;
    }

    public RtspConfig getRtspConfig() {
        return rtspConfig;
    }

    public void setRtspConfig(RtspConfig rtspConfig) {
        this.rtspConfig = rtspConfig;
    }

    public Socket getSocket() {
        return socket;
    }

    public void setSocket(Socket socket) {
        this.socket = socket;
    }

    public OutputStream getOutputStream() {
        return outputStream;
    }

    public void setOutputStream(OutputStream outputStream) {
        this.outputStream = outputStream;
    }

    public DataInputStream getInputStream() {
        return inputStream;
    }

    public void setInputStream(DataInputStream inputStream) {
        this.inputStream = inputStream;
    }

    public RtspAuthType getRtspAuthType() {
        return rtspAuthType;
    }

    public RtspProtocolType getRtspProtocolType() {
        return rtspProtocolType;
    }

    public void setRtspProtocolType(RtspProtocolType rtspProtocolType) {
        this.rtspProtocolType = rtspProtocolType;
    }

    public BareStreamCallBack getBareStreamCallBack() {
        return bareStreamCallBack;
    }

    public void setBareStreamCallBack(BareStreamCallBack bareStreamCallBack) {
        this.bareStreamCallBack = bareStreamCallBack;
    }

    public OptionsReplyCallBack getOptionsReplyCallBack() {
        return optionsReplyCallBack;
    }

    public void setOptionsReplyCallBack(OptionsReplyCallBack optionsReplyCallBack) {
        this.optionsReplyCallBack = optionsReplyCallBack;
    }

    public IRtpLoadCodecParser getVideoCodecParser() {
        return videoCodecParser;
    }

    public void setVideoCodecParser(IRtpLoadCodecParser videoCodecParser) {
        this.videoCodecParser = videoCodecParser;
    }

    public IRtpLoadCodecParser getAudioCodecParser() {
        return audioCodecParser;
    }

    public void setAudioCodecParser(IRtpLoadCodecParser audioCodecParser) {
        this.audioCodecParser = audioCodecParser;
    }

    public String getSession() {
        return session;
    }

    public String getSsrc() {
        return ssrc;
    }

    public String getUri() {
        return uri;
    }

    public void setUri(String uri) {
        this.uri = uri;
    }

    public float getScale() {
        return scale;
    }

    public void setScale(float scale) {
        this.scale = scale;
    }

    public String getAuthInfo() {
        return authInfo;
    }

    public void setAuthInfo(String authInfo) {
        this.authInfo = authInfo;
    }

    public int getVideoRtpPort() {
        return videoRtpPort;
    }

    public void setVideoRtpPort(int videoRtpPort) {
        this.videoRtpPort = videoRtpPort;
    }

    public int getAudioRtpPort() {
        return audioRtpPort;
    }

    public void setAudioRtpPort(int audioRtpPort) {
        this.audioRtpPort = audioRtpPort;
    }

    public int getRemoteVideoRtpPort() {
        return remoteVideoRtpPort;
    }

    public void setRemoteVideoRtpPort(int remoteVideoRtpPort) {
        this.remoteVideoRtpPort = remoteVideoRtpPort;
    }

    public int getRemoteAudioRtpPort() {
        return remoteAudioRtpPort;
    }

    public void setRemoteAudioRtpPort(int remoteAudioRtpPort) {
        this.remoteAudioRtpPort = remoteAudioRtpPort;
    }

    public int getSeq() {
        return seq;
    }

    public void setSeq(int seq) {
        this.seq = seq;
    }

    public byte[] getBuffer() {
        return buffer;
    }

    public void setBuffer(byte[] buffer) {
        this.buffer = buffer;
    }

    public List<String> getOptions() {
        return options;
    }

    public void setOptions(List<String> options) {
        this.options = options;
    }

    public int getTimeout() {
        return timeout;
    }

    public void setTimeout(int timeout) {
        this.timeout = timeout;
    }
}
